use crate::parser::dfa::{DFAError, NonTerm};

pub struct ProductionInfo {
    pub ret_sym: NonTerm,
    pub n_rhs: u32,
    pub symbol: Vec<&'static str>, // ASTLink.adj 中，顺序表示产生式中的字面含义
}

// 静态预生成所有产生式信息
// 如果有重复，统一是从左到右编号命名symbol为 nt0,nt1,...
lazy_static! {
    static ref PRODUCTION_TABLE: [ProductionInfo; 10] = [
        // 产生式 0: <program> ::= <function>
        ProductionInfo {
            ret_sym: NonTerm::Program,
            n_rhs: 1,
            symbol: vec!["fn_body"],
        },
        // 产生式 1: <function> ::= <data_type> <id> "(" ")" "{" <statement> "}"
        ProductionInfo {
            ret_sym: NonTerm::Function,
            n_rhs: 7,
            symbol: vec![
                "ret_type",
                "name",
                "param_list_start",
                "param_list_end",
                "body_start",
                "state_body",
                "body_end",
            ],
        },
        // 产生式 2: <statement> ::= "return" <exp> ";"
        ProductionInfo {
            ret_sym: NonTerm::Statement,
            n_rhs: 3,
            symbol: vec![
                "state_type",
                "exp_body",
                "state_end",
            ],
        },
        // 3 <exp> ::= <term>
        ProductionInfo {
            ret_sym: NonTerm::Exp,
            n_rhs : 1,
            symbol: vec!["term_body"],
        },

        // 4 <exp> ::= <exp> ("+" | "-") <term>
        ProductionInfo {
            ret_sym: NonTerm::Exp,
            n_rhs: 3,
            symbol: vec!["exp_body","operation","term_body"],
        },

        // 5 <term> ::= <factor>
        ProductionInfo {
            ret_sym: NonTerm::Term,
            n_rhs: 1,
            symbol: vec!["factor_body"],
        },

        // 6 <term> ::= <term> ("*" | "/") <factor>
        ProductionInfo {
            ret_sym: NonTerm::Term,
            n_rhs: 3,
            symbol: vec!["term_body","operation","factor_body"],
        },

        // 7 <factor> ::= <int>
        ProductionInfo {
            ret_sym: NonTerm::Factor,
            n_rhs: 1,
            symbol: vec!["uint_body"],
        },

        // 8 <factor> ::= <unary_op> <factor>
        ProductionInfo {
            ret_sym: NonTerm::Factor,
            n_rhs: 2,
            symbol: vec!["operation","factor_body"],
        },

        // 9 <factor> ::= "(" <exp> ")"
        ProductionInfo {
            ret_sym: NonTerm::Factor,
            n_rhs: 3,
            symbol: vec!["exp_start","exp_body","exp_end"],
        },

    ];
}

pub fn get_production(i: &u32) -> Result<&'static ProductionInfo, DFAError> {
    (*i as usize)
        .try_into()
        .ok()
        .and_then(|idx: usize| PRODUCTION_TABLE.get(idx))
        .ok_or(DFAError::NoProduction)
}
